package avicit.bdp.oss.utils.auth;

import avicit.bdp.common.utils.SpringApplicationContext;
import avicit.bdp.oss.dto.BucketAuthDto;
import avicit.bdp.oss.dto.BucketDto;
import avicit.bdp.oss.dto.ObjectDto;
import avicit.bdp.oss.service.auth.ObjectUserRelService;
import avicit.bdp.oss.utils.common.AcitonEnum;
import avicit.bdp.oss.utils.common.Constants;
import avicit.bdp.oss.utils.errors.PermException;
import avicit.platform6.core.context.ThreadContextHelper;

import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间：2020-11-12
 * @类说明：PermissionCheckUtils
 * @修改记录：
 * @注意事项：
 * @功能：权限检查
 */
public class PermissionCheckUtils {

  private static ObjectUserRelService objectUserRelService;

  private static Map<StrategyEnum, Set<AcitonEnum>> bucketAuthMap;

  static {
    bucketAuthMap = new HashMap<>();

    // 设置StrategyEnum.PUBLIC_READ关联操作
    Set<AcitonEnum> tmpSet1 = new HashSet<>();
    tmpSet1.add(AcitonEnum.GET_BUCKET);
    tmpSet1.add(AcitonEnum.GET_OBJECT);
    tmpSet1.add(AcitonEnum.GET_BUCKET_AUTH);
    tmpSet1.add(AcitonEnum.LIST_OBJECTS);
    tmpSet1.add(AcitonEnum.SHARE_OBJECT);
    tmpSet1.add(AcitonEnum.STAT_OBJECT);
    tmpSet1.add(AcitonEnum.GET_SYS_STATS_INFO);
    tmpSet1.add(AcitonEnum.GET_BUCKET_STORAGE_STATS);
    tmpSet1.add(AcitonEnum.GET_BUCKET_METRIC_STATS);
    bucketAuthMap.put(StrategyEnum.PUBLIC_READ, tmpSet1);

    // 设置StrategyEnum.READ_ONLY关联操作
    Set<AcitonEnum> tmpSet2 = new HashSet<>();
    tmpSet2.add(AcitonEnum.GET_BUCKET);
    tmpSet2.add(AcitonEnum.GET_BUCKET_AUTH);
    tmpSet2.add(AcitonEnum.GET_OBJECT);
    tmpSet2.add(AcitonEnum.LIST_OBJECTS);
    tmpSet2.add(AcitonEnum.SHARE_OBJECT);
    tmpSet2.add(AcitonEnum.STAT_OBJECT);
    tmpSet2.add(AcitonEnum.GET_SYS_STATS_INFO);
    tmpSet2.add(AcitonEnum.GET_BUCKET_STORAGE_STATS);
    tmpSet2.add(AcitonEnum.GET_BUCKET_METRIC_STATS);
    bucketAuthMap.put(StrategyEnum.READ_ONLY, tmpSet2);

    // 设置StrategyEnum.READ_WRITE关联操作
    Set<AcitonEnum> tmpSet3 = new HashSet<>();
    tmpSet3.add(AcitonEnum.GET_BUCKET);
    tmpSet3.add(AcitonEnum.GET_BUCKET_AUTH);
    tmpSet3.add(AcitonEnum.ADD_BUCKET_AUTH);
    tmpSet3.add(AcitonEnum.UPDATE_BUCKET_AUTH);
    tmpSet3.add(AcitonEnum.GET_BUCKET_AUTH);
    tmpSet3.add(AcitonEnum.DELTE_BUCKET_AUTH);
    tmpSet3.add(AcitonEnum.MAKE_DIRECTORY);
    tmpSet3.add(AcitonEnum.REMOVE_OBJECT);
    tmpSet3.add(AcitonEnum.PUT_OBJECT);
    tmpSet3.add(AcitonEnum.GET_OBJECT);
    tmpSet3.add(AcitonEnum.LIST_OBJECTS);
    tmpSet3.add(AcitonEnum.SHARE_OBJECT);
    tmpSet3.add(AcitonEnum.STAT_OBJECT);
    tmpSet3.add(AcitonEnum.GET_SYS_STATS_INFO);
    tmpSet3.add(AcitonEnum.GET_BUCKET_STORAGE_STATS);
    tmpSet3.add(AcitonEnum.GET_BUCKET_METRIC_STATS);
    bucketAuthMap.put(StrategyEnum.READ_WRITE, tmpSet3);

    // 设置桶策略为PRIVATE、设置对象权限信息，此时被授权用户拥有桶的一下权限
    Set<AcitonEnum> tmpSet4 = new HashSet<>();
    tmpSet4.add(AcitonEnum.GET_BUCKET);
    tmpSet4.add(AcitonEnum.GET_BUCKET_AUTH);
    tmpSet4.add(AcitonEnum.LIST_OBJECTS);
    tmpSet4.add(AcitonEnum.GET_SYS_STATS_INFO);
    tmpSet4.add(AcitonEnum.GET_BUCKET_STORAGE_STATS);
    tmpSet4.add(AcitonEnum.GET_BUCKET_METRIC_STATS);
    bucketAuthMap.put(StrategyEnum.PRIVATE, tmpSet4);
  }

  /**
   * 权限校验；（1）桶策略（2）对象权限(优先级最高)
   *
   * @param bucketDto
   * @param objectDto
   * @param aciton
   */
  public static void checkPerm(
      BucketDto bucketDto, ObjectDto objectDto, BucketAuthDto bucketAuthDto, AcitonEnum aciton) {
    // step1:如果设置了对象权限，需要校验桶策略、对象权限，对象权限>桶策略
    if (objectDto != null && bucketAuthDto != null) {
      checkObjectPerm(bucketDto, objectDto, bucketAuthDto, aciton);
      return;
    }

    // step2:如果未设置对象权限，仅需校验桶策略
    checkBucketPerm(bucketDto, aciton);

    // step3:密级管理
    checkBucketSecretLevel();
  }

  /**
   * 桶策略校验
   *
   * @param bucketDto
   * @param aciton
   */
  private static void checkBucketPerm(BucketDto bucketDto, AcitonEnum aciton) {
    String userId = getUserId();

    // step1:用户自身拥有所有操作权限
    if (bucketDto.getCreatedBy().equals(userId)) {
      return;
    }

    // step2:桶策略为私有时，其他用户无任何权限
    StrategyEnum bucketStrategy = StrategyEnum.getStrategyType(bucketDto.getBucketStrategy());
    if (bucketStrategy == StrategyEnum.PRIVATE) {
      getObjectUserRelService();
      Integer count =
          objectUserRelService.countObjectUserRelDto(bucketDto.getBucketName(), null, null, userId);
      if (count != null || count > 0) {
        Set<AcitonEnum> tmpSet = bucketAuthMap.get(StrategyEnum.PRIVATE);
        if (!tmpSet.contains(aciton)) {
          throw new PermException(
              String.format(
                  "当前用户%s对桶%s无操作权限%s",
                  chgUserName(userId), bucketDto.getBucketName(), aciton.getAction()));
        }
      }
    }

    // step3:桶策略为公共读时，其他用户只有读权限
    if (bucketStrategy == StrategyEnum.PUBLIC_READ) {
      Set<AcitonEnum> tmpSet = bucketAuthMap.get(StrategyEnum.PUBLIC_READ);
      if (!tmpSet.contains(aciton)) {
        throw new PermException(
            String.format(
                "当前用户%s对桶%s无操作权限%s",
                chgUserName(userId), bucketDto.getBucketName(), aciton.getAction()));
      }
    }
  }

  /**
   * 对象权限校验
   *
   * @param bucketDto
   * @param objectDto
   * @param bucketAuthDto
   * @param aciton
   */
  private static void checkObjectPerm(
      BucketDto bucketDto, ObjectDto objectDto, BucketAuthDto bucketAuthDto, AcitonEnum aciton) {
    String userId = getUserId();

    // step1:对象创建者==被授权用户，拥有完全权限
    if (objectDto.getCreatedBy().equals(userId)) {
      return;
    }

    // step2:对象的授权用户不包括当前用户，仅需校验桶策略
    List<String> ids = Arrays.asList(bucketAuthDto.getAuthUser().trim().split(Constants.COMMA));
    if (!ids.contains(userId)) {
      checkBucketPerm(bucketDto, aciton);
      return;
    }

    // step3：对象的授权用户包括当前用户，需要对象权限校验
    // step3-1:授权信息为READ_ONLY(只读)
    StrategyEnum strategy = StrategyEnum.getStrategyType(bucketAuthDto.getStrategy());
    if (strategy == StrategyEnum.READ_ONLY) {
      Set<AcitonEnum> tmpSet = bucketAuthMap.get(StrategyEnum.READ_ONLY);
      if (!tmpSet.contains(aciton)) {
        throw new PermException(
            String.format(
                "当前用户%s对对象%s无操作权限%s",
                chgUserName(userId), bucketAuthDto.getBucketName(), aciton.getAction()));
      }
    }

    // step3-2：授权信息为READ_WRITE(读写)
    if (strategy == StrategyEnum.READ_ONLY) {
      Set<AcitonEnum> tmpSet = bucketAuthMap.get(StrategyEnum.READ_ONLY);
      if (!tmpSet.contains(aciton)) {
        throw new PermException(
            String.format(
                "当前用户%s对对象%s无操作权限%s",
                chgUserName(userId), bucketAuthDto.getBucketName(), aciton.getAction()));
      }
    }
  }

  /** 桶密级检查 */
  private static boolean checkBucketSecretLevel() {
    // TODO:后续与大数据平台统一设计、开发
    return true;
  }

  /**
   * 获取当前登录用户信息
   *
   * @return
   */
  private static String getUserId() {
    return ThreadContextHelper.getUserId() == null
        ? Constants.DEFALUT_USER_ID
        : ThreadContextHelper.getUserId();
  }

  /**
   * 获取对象-用户映射关系服务
   *
   * @return
   */
  private static synchronized void getObjectUserRelService() {
    if (objectUserRelService == null) {
      objectUserRelService =
          (ObjectUserRelService) SpringApplicationContext.getBean("objectUserRelService");
    }
  }

  /**
   * 用户名转换
   *
   * @param userId
   * @return
   */
  private static String chgUserName(String userId) {
    getObjectUserRelService();
    return objectUserRelService.getUserNameByIds(userId);
  }
}
